package org.sky.security.support;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.logging.log4j.Logger;
import org.sky.sys.entity.SysRole;
import org.sky.sys.entity.SysRoleResource;
import org.sky.sys.mapper.SysResourceMapper;
import org.sky.sys.mapper.SysRoleMapper;
import org.sky.sys.mapper.SysRoleResourceMapper;
import org.sky.util.LogUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;
import org.springframework.stereotype.Service;

/**
 * @author weifx
 * @Title: CustomInvocationSecurityMetadataSourceService
 * @ProjectName springboot-platform
 * @Description: TODO{最核心的地方，就是提供某个资源对应的权限定义，
 *                    即getAttributes方法返回的结果。
 *                    此类在初始化时，应该取到所有资源及其对应角色的定义。}
 * @date 2019/3/1 12:40
 * @Version 1.0
 */
@Service
public class CustomInvocationSecurityMetadataSourceService implements
        FilterInvocationSecurityMetadataSource {
    Logger log = LogUtils.getLogger(CustomInvocationSecurityMetadataSourceService.class);
    @Autowired
    private SysResourceMapper sysResourceMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private SysRoleResourceMapper sysRoleResourceMapper;
    /**
     * 资源与角色对应关系
     */
    private static Map<String, Collection<ConfigAttribute>> resourceMap = null;

    /**
     * 被@PostConstruct修饰的方法会在服务器加载Servle的时候运行，并且只会被服务器执行一次。
     * PostConstruct在构造函数之后执行,init()方法之前执行。
     */
    //一定要加上@PostConstruct注解
    @PostConstruct
    private void loadResourceDefine() {
        //在Web服务器启动时，提取系统中的所有权限。
        List<SysRole> ruleList =sysRoleMapper.selectAll();
        /*
         * 应当是资源为key， 权限为value。
         * 资源通常为url， 权限就是那些以ROLE_为前缀的角色。
         * 一个资源可以由多个权限来访问。
         * sparta
         */
        resourceMap = new HashMap<String, Collection<ConfigAttribute>>();
        /**
         * 角色字段关联表
         */
        List<SysRoleResource> sysRoleResourceList = sysRoleResourceMapper.selectFullFieldByExample(null);
        if(ruleList!=null && ruleList.size()>0) {
            for (SysRole role : ruleList) {
                ConfigAttribute ca = new SecurityConfig(role.getCode());
                for (SysRoleResource roleResource : sysRoleResourceList) {
                    /*
                     * 判断资源文件和权限的对应关系，
                     * 如果已经存在相关的资源url，则要通过该url为key提取出权限集合，将权限增加到权限集合中。
                     * sparta
                     */
                    String url = "/"+roleResource.getResUrl();
                    if (resourceMap.containsKey(url)) {
                        Collection<ConfigAttribute> value = resourceMap.get(url);
                        value.add(ca);
                        resourceMap.put(url, value);
                    } else {
                        Collection<ConfigAttribute> atts = new ArrayList<ConfigAttribute>();
                        atts.add(ca);
                        resourceMap.put(url, atts);
                    }
                }
            }
        }
    }

    @Override
    public Collection<ConfigAttribute> getAllConfigAttributes() {
        return new ArrayList<ConfigAttribute>();
    }
    // 根据URL，找到相关的权限配置。
    @Override
    public Collection<ConfigAttribute> getAttributes(Object object)
            throws IllegalArgumentException {
        // object 是一个URL，被用户请求的url。
        FilterInvocation filterInvocation = (FilterInvocation) object;
        if (resourceMap == null) {
            loadResourceDefine();
        }
        Iterator<String> ite = resourceMap.keySet().iterator();
        while (ite.hasNext()) {
            String resURL = ite.next();
            RequestMatcher requestMatcher = new AntPathRequestMatcher(resURL);
            if(requestMatcher.matches(filterInvocation.getHttpRequest())) {
                return resourceMap.get(resURL);
            }
        }
        return null;
    }
    @Override
    public boolean supports(Class<?> arg0) {

        return true;
    }
}
